package com.tuanzi.loan.business.service.sms.impl;

import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.starbaba.model.utils.JSONUtils;
import com.tuanzi.loan.business.constants.sms.SmsVoiceSendTaskStatus;
import com.tuanzi.loan.business.entity.sms.SmsSendTask;
import com.tuanzi.loan.business.entity.sms.SmsSendTaskStatus;
import com.tuanzi.loan.business.entity.sms.SmsTaskNumber;
import com.tuanzi.loan.business.entity.sms.SmsVoiceSendTask;
import com.tuanzi.loan.business.repository.sms.SmsTaskNumberRepository;
import com.tuanzi.loan.business.repository.sms.SmsVoiceSendTaskRepository;
import com.tuanzi.loan.business.service.sms.SmsVoiceSendTaskService;
import com.tuanzi.loan.core.aspect.Debug;
import com.tuanzi.loan.core.service.CommonServiceImpl;
import com.tuanzi.loan.core.util.ThrowableUtils;
import com.tuanzi.loan.core.vo.PageSearcher;
import com.tuanzi.loan.vo.request.family.sms.SmsVoiceSendTaskSearchRequest;
import com.tuanzi.loan.vo.response.family.sms.SmsVoiceSendTaskSearchResponse;
import com.tuanzi.server.loan_base.constant.sms.SmsPlatformChannel;
import com.tuanzi.server.loan_base.constant.sms.SmsVoicePlatformChannel;
import com.tuanzi.server.loan_base.util.sms.voice.SendBatchVoiceMessage;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.retry.RetryException;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: chenweijun
 * @Date: 2018/10/22 11:41
 * @Description:
 */
@Debug
@Slf4j
@Service
@Transactional
@Retryable(value = { RetryException.class })
public class SmsVoiceSendTaskServiceImpl extends CommonServiceImpl<SmsVoiceSendTask, Long> implements SmsVoiceSendTaskService {

    private static String SUCCESS_STATUS = "Success";

    @Autowired
    private SmsVoiceSendTaskRepository smsVoiceSendTaskRepository;

    @Autowired
    private SmsTaskNumberRepository smsTaskNumberRepository;

    @Override
    protected JpaRepository<SmsVoiceSendTask, Long> getRepository() {
        return smsVoiceSendTaskRepository;
    }

    @Override
    public SmsVoiceSendTask addSmsVoiceSendTask(Long calculateTaskId) {
        SmsVoiceSendTask task = smsVoiceSendTaskRepository.findTopByCalculateTaskIdAndStatus(calculateTaskId, SmsVoiceSendTaskStatus.WAITING_SUBMIT);

        if (task != null) {
            return task;
        }
        task = new SmsVoiceSendTask();
        task.setStatus(SmsVoiceSendTaskStatus.WAITING_SUBMIT);
        task.setCalculateTaskId(calculateTaskId);
        task.setCreateTime(new Date());
        return smsVoiceSendTaskRepository.save(task);
    }

    @Override
    @Transactional(propagation= Propagation.NOT_SUPPORTED)
    public void sendVoiceSms(SmsVoiceSendTask smsVoiceSendTask) {

        try {
            List<String> mobNums = smsTaskNumberRepository.findAllByTaskId(smsVoiceSendTask.getCalculateTaskId()).stream().
                    map(SmsTaskNumber::getMobnum).distinct().collect(Collectors.toList());

            //分割单次提交数量（短信平台提交接口限制）
            List<String> smsTaskNumbers = Lists.newArrayList();
            if(smsVoiceSendTask.getPlatformChannel() == SmsVoicePlatformChannel.OUYI.getId()){

                smsTaskNumbers = splitSmsTaskNumbers(mobNums, 500);

            }else if(smsVoiceSendTask.getPlatformChannel() == SmsVoicePlatformChannel.KEFAN.getId()){  //科帆每次只能拨号一个号码
                smsTaskNumbers = mobNums;
            }else if(smsVoiceSendTask.getPlatformChannel() == SmsVoicePlatformChannel.YIDAOZHENGTONG.getId()){
                smsTaskNumbers = splitSmsTaskNumbers(mobNums, 10000);
            }

            List<String> taskIds = Lists.newArrayList();

            smsTaskNumbers.stream().forEach(x -> {
                try {
                    // 调用发送接口
                    String result =  SendBatchVoiceMessage.send(x, smsVoiceSendTask.getPlatformChannel(), smsVoiceSendTask.getVoiceId(), smsVoiceSendTask.getId());

                    // 构造短信平台返回对象
                    SmsVoiceSendTaskService.SmsVoicePlatformResult resultObj = structureSmsPlatformResult(result, smsVoiceSendTask.getPlatformChannel());
                    if (resultObj == null) {
                        smsVoiceSendTask.setStatus(SmsVoiceSendTaskStatus.SEND_FAIL);
                        smsVoiceSendTask.setErrorReason("短信平台接口没返回任何信息,请与短信平台联系");
                    } else {
                        if (resultObj.isSuccess()) {
                            smsVoiceSendTask.setStatus(SmsVoiceSendTaskStatus.SEND_DONE);
                            if(StringUtils.isNotBlank(resultObj.getTaskId())){
                                taskIds.add(resultObj.getTaskId() + StringUtils.EMPTY);
                            }
                        } else {
                            smsVoiceSendTask.setStatus(SmsVoiceSendTaskStatus.SEND_FAIL);
                            smsVoiceSendTask.setErrorReason(
                                    (StringUtils.isBlank(smsVoiceSendTask.getErrorReason()) ? StringUtils.EMPTY : smsVoiceSendTask.getErrorReason()) + resultObj.getMessage());
                        }
                    }

                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            });
            smsVoiceSendTask.setTaskId(taskIds.stream().collect(Collectors.joining(",")));
        } catch (Throwable e) {
            log.error(e.getMessage(), e);
            smsVoiceSendTask.setErrorReason(ThrowableUtils.getStackTraceString(e));
            smsVoiceSendTask.setStatus(SmsVoiceSendTaskStatus.SEND_FAIL);
        } finally {
            smsVoiceSendTaskRepository.save(smsVoiceSendTask);
        }

    }

    @Override
    public Long countByStatus(SmsVoiceSendTaskStatus status) {
        return smsVoiceSendTaskRepository.countByStatus(status);
    }

    @Override
    public SmsVoiceSendTask findTopOneByStatusAndExecuteTimeBefore(SmsVoiceSendTaskStatus status, Date executeDate) {
        return smsVoiceSendTaskRepository.findTopOneByStatusAndExecuteTimeBefore(status, executeDate);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateStatusWithoutTransactional(SmsVoiceSendTask smsVoiceSendTask, SmsVoiceSendTaskStatus status) {
        smsVoiceSendTask.setStatus(status);
        smsVoiceSendTaskRepository.save(smsVoiceSendTask);
    }

    @Override
    public Page<SmsVoiceSendTaskSearchResponse> list(PageSearcher<SmsVoiceSendTaskSearchRequest> pageSearcher) {
        return smsVoiceSendTaskRepository.list(pageSearcher.getSearchCondition(), pageSearcher.getPageable());
    }

    @Override
    public void cancelTask(Long smsVoiceSendTaskId) {
        SmsVoiceSendTask smsVoiceSendTask = smsVoiceSendTaskRepository.findOne(smsVoiceSendTaskId);
        smsVoiceSendTask.setStatus(SmsVoiceSendTaskStatus.SEND_CANCEL);
        smsVoiceSendTaskRepository.save(smsVoiceSendTask);
    }

    @Override
    public SmsVoiceSendTask resend(Long smsVoiceSendTaskId) {
        SmsVoiceSendTask smsVoiceSendTask = smsVoiceSendTaskRepository.findOne(smsVoiceSendTaskId);
        smsVoiceSendTask.setStatus(SmsVoiceSendTaskStatus.READY_SEND);
        return smsVoiceSendTaskRepository.save(smsVoiceSendTask);
    }

    @Override
    public Map<String, String> findDistinctFirstNames() {
        List<String> firstPartyNames =  smsVoiceSendTaskRepository.findDistinctFirstPartyNames();
        Map<String, String> firstPartyNameMap = new HashMap<String, String>();
        for(String firstPartyName: firstPartyNames) {
            firstPartyNameMap.put(firstPartyName, firstPartyName);
        }
        return firstPartyNameMap;
    }

    /**
     *
     * @param smsTaskNumbers 手机号集合
     * @param eachListMaxCount 每次分割的条数
     * @return
     */
    private List<String /* phone numbers */> splitSmsTaskNumbers(List<String> smsTaskNumbers, Integer eachListMaxCount) {
        List<String> splitedSmsTaskNumbers = Lists.newArrayList();

        if (com.base.common.util.CollectionUtils.isEmpty(smsTaskNumbers)) {
            return splitedSmsTaskNumbers;
        }

        Float total = smsTaskNumbers.size() + 0.0F;

        if (total <= eachListMaxCount) {
            splitedSmsTaskNumbers.add(structurePhoneNumbers(smsTaskNumbers));
            return splitedSmsTaskNumbers;
        }

        Integer foreachCount = (int) Math.ceil(total / eachListMaxCount);
        for (int i = 0; i < foreachCount; i++) {
            Integer startIndex = i * eachListMaxCount;
            Integer tmpEndIndex = (i + 1) * eachListMaxCount;
            Integer endIndex = tmpEndIndex > smsTaskNumbers.size() ? smsTaskNumbers.size() : tmpEndIndex;
            List<String> eachSmsTaskNumbers = smsTaskNumbers.subList(startIndex, endIndex);
            splitedSmsTaskNumbers.add(structurePhoneNumbers(eachSmsTaskNumbers));
        }

        return splitedSmsTaskNumbers;
    }

    private String structurePhoneNumbers(List<String> phoneNumbers) {
        return phoneNumbers.parallelStream().collect(Collectors.joining(","));
    }

    /**
     * 构造短信平台返回结果
     * @param resultString 结果
     * @param smsPlatformChannel 短信平台
     * @return
     */
    private SmsVoiceSendTaskService.SmsVoicePlatformResult structureSmsPlatformResult(String resultString, Integer smsPlatformChannel) {
        if (StringUtils.isBlank(resultString)) {
            return null;
        }

        try {
            SmsVoiceSendTaskService.SmsVoicePlatformResult result = new SmsVoiceSendTaskService.SmsVoicePlatformResult();
            if(smsPlatformChannel == SmsVoicePlatformChannel.OUYI.getId()) {  //欧一平台

                result = structOuYiResult(resultString);

            }else if(smsPlatformChannel == SmsVoicePlatformChannel.KEFAN.getId()){  //科帆

                result = structKeFanResult(resultString);
            }else if (smsPlatformChannel == SmsVoicePlatformChannel.YIDAOZHENGTONG.getId()){ //一道正通

                result = structYiDaoZhengTongResult(resultString);
            }else{
                return null;
            }
            return result;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 构造一道正通响应参数
     * @param resultString 结果串
     * @return
     */
    private SmsVoicePlatformResult structYiDaoZhengTongResult(String resultString) {
        //{ "data":{ "batchId":586128, "successCount":1 }, "error":"E00000000", "msg":"成功", "status":"1" }
        JsonObject responseJson = JSONUtils.toJsonObject(resultString);
        SmsVoicePlatformResult smsVoicePlatformResult = new SmsVoicePlatformResult();
        String code = JSONUtils.checkAsString(responseJson, "status");
        String msg = JSONUtils.checkAsString(responseJson, "msg");
        smsVoicePlatformResult.setMessage(msg);
        if("1".equals(code)){
            smsVoicePlatformResult.setStatus(SUCCESS_STATUS);
        }

        return smsVoicePlatformResult;
    }


    /**
     * 构造欧一语音通道响应参数
     * @param response
     * @return
     */
    public SmsVoicePlatformResult structOuYiResult(String response) {
        SmsVoicePlatformResult smsVoicePlatformResult = new SmsVoicePlatformResult();
        JsonObject responseJson = JSONUtils.toJsonObject(response);

        String code = JSONUtils.checkAsString(responseJson, "code");
        String msg = JSONUtils.checkAsString(responseJson, "msg");

        if ("0".equals(code)) {
            smsVoicePlatformResult.setStatus(SUCCESS_STATUS);
        } else {
            smsVoicePlatformResult.setMessage(msg);
        }
        return smsVoicePlatformResult;
    }


    /**
     * 构造科帆语音通道响应参数
     * @param response
     * @return
     */
    public SmsVoicePlatformResult structKeFanResult(String response){
        SmsVoicePlatformResult smsVoicePlatformResult = new SmsVoicePlatformResult();
        JsonObject responseJson = JSONUtils.toJsonObject(response); //{"transcode":"148431639","retcode":0}
        String retcode = responseJson.get("retcode").getAsString();
        if("0".equals(retcode)){
            smsVoicePlatformResult.setStatus(SUCCESS_STATUS);
        }else{
            smsVoicePlatformResult.setMessage(retcode);
        }
        return smsVoicePlatformResult;
    }

}
